package com.pig4cloud.pig.ads.service.impl;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;

import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import com.alibaba.nacos.common.utils.Objects;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.pig4cloud.pig.ads.pig.mapper.AdMaterialPlatformMapper;
import com.pig4cloud.pig.ads.pig.mapper.AdMaterialPushBoxMapper;
import com.pig4cloud.pig.ads.service.AdMaterialPushBoxService;
import com.pig4cloud.pig.ads.service.AdMaterialPushWorkerService;
import com.pig4cloud.pig.ads.service.AdMaterialService;
import com.pig4cloud.pig.api.dto.AdMaterialPushBoxDTO;
import com.pig4cloud.pig.api.entity.AdMaterial;
import com.pig4cloud.pig.api.entity.AdMaterialPlatform;
import com.pig4cloud.pig.api.entity.AdMaterialPushBox;
import com.pig4cloud.pig.api.entity.AdMaterialPushBoxInfo;
import com.pig4cloud.pig.api.util.Constants;
import com.pig4cloud.pig.api.vo.AdMaterialPushBoxVO;
import com.pig4cloud.pig.common.core.constant.enums.PlatformTypeEnum;
import com.pig4cloud.pig.common.core.util.R;
import com.pig4cloud.pig.common.security.util.SecurityUtils;

import cn.hutool.json.JSONUtil;

@Service
public class AdMaterialPushBoxServiceImpl extends ServiceImpl<AdMaterialPushBoxMapper, AdMaterialPushBox>  implements AdMaterialPushBoxService {
	
	@Autowired
	private AdMaterialPushBoxMapper adMaterialPushBoxMapper;
	
	@Autowired
	private AdMaterialService adMaterialService;
	
	@Autowired
	private AdMaterialPlatformMapper adMaterialPlatformMapper;
	
	@Autowired
	private AdMaterialPushWorkerService adMaterialPushWorkerService;
	
	@Autowired
	private RedisTemplate<String, String> redisTemplate;
	
	
	@Override
	public R getMaterialPushBoxInfo() {
		String loginUserId = getLoginUserId();
		List<AdMaterialPushBoxVO> materialPushBoxInfo = adMaterialPushBoxMapper.getMaterialPushBoxInfo(loginUserId);
		//构造返回结果
		if(CollectionUtils.isEmpty(materialPushBoxInfo)){
			return R.ok(new AdMaterialPushBoxInfo());
		}
		AdMaterialPushBoxInfo result = new AdMaterialPushBoxInfo();
		List<AdMaterialPushBoxVO> adMaterialPreparePush = new ArrayList<>();
		List<AdMaterialPushBoxVO> adMaterialProgressPush = new ArrayList<>();;
		List<AdMaterialPushBoxVO> adMaterialFinishPush = new ArrayList<>();
		
		for (AdMaterialPushBoxVO adMaterialPushBoxVO : materialPushBoxInfo) {
			
			Integer pushStatus = adMaterialPushBoxVO.getPushStatus();
			Integer platformId = adMaterialPushBoxVO.getPlatformId();
			String platformName = PlatformTypeEnum.descByValue(String.valueOf(platformId));
			adMaterialPushBoxVO.setPlatformName(platformName);
			switch (pushStatus) {
				case Constants.PREPARE_PUSH:
					adMaterialPreparePush.add(adMaterialPushBoxVO);
					break;
				case Constants.PROGRESS_PUSH:
					adMaterialProgressPush.add(adMaterialPushBoxVO);
					break;
				case Constants.FAIL_HPUSH:
					adMaterialProgressPush.add(adMaterialPushBoxVO);
					break;
				case Constants.FINISH_PUSH:
					adMaterialFinishPush.add(adMaterialPushBoxVO);
					break;
				default:
					break;
			}
		}
		result.setAdMaterialPreparePush(adMaterialPreparePush);
		result.setAdMaterialProgressPush(adMaterialProgressPush);
		result.setAdMaterialFinishPush(adMaterialFinishPush);
		result.setNum(adMaterialPreparePush.size());
		return R.ok(result);
	}

	/**
	 * 删除单条待推送数据
	 */
	@Override
	public void deleteAdMaterialPushBox(Integer id) {
		AdMaterialPushBox adMaterialPushBox =new AdMaterialPushBox();
		adMaterialPushBox.setId(id);
		adMaterialPushBox.setIsDeleted(1);
		adMaterialPushBox.setUpdateTime(new Date());
		String loginUserId = getLoginUserId();
		adMaterialPushBox.setUpdateUser(loginUserId);
		adMaterialPushBox.setPushStatus(Constants.PREPARE_PUSH);
		adMaterialPushBox.setCreateUser(loginUserId);
		adMaterialPushBoxMapper.deleteAdMaterialPushBox(adMaterialPushBox);
	}

	/**
	 * 清空素待推送素材
	 */
	@Override
	public void clearAdMaterialPushBox() {
		AdMaterialPushBox adMaterialPushBox =new AdMaterialPushBox();
		adMaterialPushBox.setIsDeleted(1);
		adMaterialPushBox.setUpdateTime(new Date());
		String loginUserId = getLoginUserId();
		adMaterialPushBox.setUpdateUser(loginUserId);
		adMaterialPushBox.setPushStatus(Constants.PREPARE_PUSH);
		adMaterialPushBox.setCreateUser(loginUserId);
		adMaterialPushBoxMapper.deleteAdMaterialPushBox(adMaterialPushBox);
	}

	@Override
	public R saveAdMaterialPushBox(Long materialId) {
		AdMaterial adMaterial = adMaterialService.getById(materialId);
		if(Objects.isNull(adMaterial)){
			return R.failed("未关联到素材，保存失败");
		}
		String loginUserId = getLoginUserId();
		List<AdMaterialPushBox> prepareMaterialPushBox = adMaterialPushBoxMapper.getPrepareMaterialPushBox(loginUserId);
		for (AdMaterialPushBox adMaterialPushBox : prepareMaterialPushBox) {
			if(adMaterialPushBox.getMaterialId().longValue() == materialId.longValue()){
				return R.ok();
			}
		}
		
		AdMaterialPushBox adMaterialPushBox =new AdMaterialPushBox();
		adMaterialPushBox.setMaterialId(materialId);
		adMaterialPushBox.setPushStatus(Constants.PREPARE_PUSH);
		adMaterialPushBox.setCreateUser(loginUserId);
		adMaterialPushBox.setCreateTime(new Date());
		this.save(adMaterialPushBox);
		return R.ok();
	}

	
	@Override
	public R pushAdMaterialPushBox(AdMaterialPushBoxDTO req) {
		
		//媒体账号
		List<Long> advertiserIds = req.getAdvertiserIds();
		//平台id
		Integer platformId = req.getPlatformId();
		//素材id
		Long materialId = req.getMaterialId();
		
		if(Objects.isNull(materialId) || Objects.isNull(platformId) ||  CollectionUtils.isEmpty(advertiserIds)){
			return R.failed("缺失参数，推送失败");
		}
		
		AdMaterial adMaterial = adMaterialService.getById(materialId);
		if(Objects.isNull(adMaterial)){
			return R.failed("未关联到素材，保存失败");
		}
		
		List<Long> materialIds = new ArrayList<>();
		materialIds.add(materialId);
		//排除已推送的数据
		List<AdMaterialPlatform> adMaterialPlatformList = adMaterialPlatformMapper.getListByMidAndIds(advertiserIds,materialIds);
		HashSet<String> adList = new HashSet<>();
		adMaterialPlatformList.forEach(a-> adList.add(String.valueOf(a.getAdvertiserId())));
		String loginUserId = getLoginUserId();
		Date date = new Date();
		//生成需要推送数据
		List<AdMaterialPushBox> entitys = new ArrayList<>();
		for (Long advertiserId: advertiserIds) {
			if(adList.contains(String.valueOf(advertiserId))){
				continue;
			}
			//查询是否在推送中,不在则保存到推送中缓存
			String key = getCachePushKey(loginUserId, advertiserId, materialId);
			Object obj = redisTemplate.opsForValue().get(key);
			if(Objects.nonNull(obj)){
				continue;
			}
			AdMaterialPushBox entity = new AdMaterialPushBox();
			entity.setMaterialId(materialId);
			entity.setPlatformId(platformId);
			entity.setAdvertiserId(String.valueOf(advertiserId));
			entity.setPushStatus(Constants.PROGRESS_PUSH);
			entity.setCreateUser(loginUserId);
			entity.setCreateTime(date);
			entitys.add(entity);
			redisTemplate.opsForValue().set(key,JSONUtil.toJsonStr(entity),1*60*60,TimeUnit.SECONDS);
		}
		//全部推送过，直接返回成功
		if(CollectionUtils.isEmpty(entitys)){
			return R.ok();
		}
		//入库,保存为推送中状态
		this.saveBatch(entitys);
		//开始异步推送
		for (AdMaterialPushBox bean : entitys) {
			adMaterialPushWorkerService.asyncPushAdMateria(loginUserId, bean.getAdvertiserId(), bean.getPlatformId(),  adMaterialService.getById(bean.getMaterialId()));
		}
		return R.ok();
	}
	
	@Override
	public R pushAllAdMaterialPushBox(AdMaterialPushBoxDTO req) {
		
		//媒体账号
		List<Long> advertiserIds = req.getAdvertiserIds();
		//平台id
		Integer platformId = req.getPlatformId();
		
		if( Objects.isNull(platformId) ||  CollectionUtils.isEmpty(advertiserIds)){
			return R.failed("缺失参数，推送失败");
		}
		
		//查询用户所有待推送素材
		String loginUserId = getLoginUserId();
		List<AdMaterialPushBox> prepareMaterialPushBox = adMaterialPushBoxMapper.getPrepareMaterialPushBox(loginUserId);
		Map<Long,AdMaterialPushBoxDTO> map = new HashMap<>();
		List<AdMaterialPushBox> entityList = new ArrayList<>();
		for (AdMaterialPushBox entity : prepareMaterialPushBox) {
			AdMaterialPushBox e = new AdMaterialPushBox();
			e.setId(entity.getId());
			e.setIsDeleted(1);
			entityList.add(e);
			Long materialId = entity.getMaterialId();
			if(map.containsKey(materialId)){
				AdMaterialPushBoxDTO adMaterialPushBoxDTO = map.get(materialId);
				List<Long> ids = adMaterialPushBoxDTO.getAdvertiserIds();
				ids.addAll(advertiserIds);
			}else{
				AdMaterialPushBoxDTO dto = new AdMaterialPushBoxDTO();
				dto.setAdvertiserIds(advertiserIds);
				dto.setPlatformId(req.getPlatformId());
				dto.setMaterialId(materialId);
				map.put(materialId, dto);
			}
		}
		//更新状态为删除状态，实际应该彻底删除，暂时保留中间数据排查bug
		this.updateBatchById(entityList);
		Collection<AdMaterialPushBoxDTO> values = map.values();
		for (AdMaterialPushBoxDTO dto : values) {
			pushAdMaterialPushBox(dto);
		}
		return R.ok();
	}

	/**
	 * 获取推送中缓存key
	 * @return
	 */
	private String getCachePushKey(String loginUserId, Long advertiserId, Long materialId){
		return Constants.AD_MATERIAL_PROGRESS_PUSH_PRIX + loginUserId + "_" + advertiserId + "_" + materialId;
	}
	
	private String getLoginUserId(){
		return String.valueOf(SecurityUtils.getUser().getId());
	}

	@Override
	public Set<Long> getPreparePushMaterial(String loginUserId) {
		List<AdMaterialPushBoxVO> materialPushBoxInfo = adMaterialPushBoxMapper.getMaterialPushBoxInfo(loginUserId);
		Set<Long> res = new HashSet<>();
		for (AdMaterialPushBoxVO adMaterialPushBoxVO : materialPushBoxInfo) {
			Long materialId = adMaterialPushBoxVO.getMaterialId();
			res.add(materialId);
		}
		return res;
	}

	@Override
	public R batchPushMaterial(AdMaterialPushBoxDTO req) {
		//媒体账号
		List<Long> advertiserIds = req.getAdvertiserIds();
		//平台id
		Integer platformId = req.getPlatformId();
		//素材id
		List<Long> materialIdList = req.getMaterialIdList();
		
		if(CollectionUtils.isEmpty(materialIdList) || Objects.isNull(platformId) ||  CollectionUtils.isEmpty(advertiserIds)){
			return R.failed("缺失参数，推送失败");
		}
		for (Long materialId : materialIdList) {
			AdMaterialPushBoxDTO dto = new AdMaterialPushBoxDTO();
			dto.setAdvertiserIds(advertiserIds);
			dto.setPlatformId(req.getPlatformId());
			dto.setMaterialId(materialId);
			pushAdMaterialPushBox(dto);
		}
		return R.ok();
	}

}
